import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
import os
import re

def parse_references(reference_file_path):
    """
    解析参考文献文件中的引用信息
    
    参数:
        reference_file_path (str): 参考文献文件路径
    
    返回:
        tuple: (引用字典, 处理状态消息)
    """
    references_map = {}
    # 正则表达式匹配参考文献条目
    reference_line_regex = re.compile(
        r"^(\d+)\.\s*.*?(?:,\s*\d{1,2}-\d{1,2},\s*\d{4})?，\s*(?:\[.*?\]\((https?://[^\s)]+)\)|(https?://[^\s]+))"
    )
    try:
        with open(reference_file_path, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                match = reference_line_regex.match(line)
                if match:
                    number_str = match.group(1)
                    markdown_url = match.group(2)
                    raw_url = match.group(3)
                    url = markdown_url if markdown_url else raw_url
                    if number_str and url:
                        try:
                            references_map[int(number_str)] = url.strip()
                        except ValueError:
                            # These print statements will go to console if GUI is run from one
                            print(f"警告: 无法解析参考文献编号 '{number_str}' 在行: {line}")
    except FileNotFoundError:
        return None, f"错误: 未找到参考文献文件 {reference_file_path}"
    except Exception as e:
        return None, f"解析参考文献时发生错误: {e}"
    
    if not references_map:
        return None, "未找到有效参考文献或文件为空"
    return references_map, "参考文献解析成功"

# 替换文本中的引用编号为超链接
def replace_citations_in_text(text_content, references_map):
    """
    将文本中的引用编号替换为Markdown超链接
    
    参数:
        text_content (str): 原始文本内容
        references_map (dict): 参考文献字典 {编号: URL}
    
    返回:
        str: 替换后的文本内容
    """
    # 匹配引用编号的正则表达式
    citation_regex = re.compile(
        r"([^\w\s])(\d+)(?=\s|$|[^\w\s])|(\s)(\d+)(?=\s|$|[^\w\s])"
    )

    def replacer(match):
        full_text = match.string 
        # 提取匹配的不同情况
        punctuation_char = match.group(1)
        number_after_punctuation_str = match.group(2)
        space_char = match.group(3)
        number_after_space_str = match.group(4)
        
        current_number_str = None
        is_space_case = False
        leading_char_to_preserve = ""
        num_start_idx_in_string = -1
        num_end_idx_in_string = -1 

        # 处理带标点的情况
        if punctuation_char and number_after_punctuation_str:
            current_number_str = number_after_punctuation_str
            leading_char_to_preserve = punctuation_char
            num_start_idx_in_string = match.start(2) 
            num_end_idx_in_string = match.end(2)     
        # 处理带空格的情况    
        elif space_char and number_after_space_str:
            current_number_str = number_after_space_str
            is_space_case = True
            num_start_idx_in_string = match.start(4) 
            num_end_idx_in_string = match.end(4)     
        
        if not current_number_str:
            return match.group(0) 

        # 检查后续字符防止误匹配
        if (num_end_idx_in_string + 1) < len(full_text): 
            if full_text[num_end_idx_in_string] == '.' and \
               full_text[num_end_idx_in_string + 1].isdigit():
                return match.group(0) 

        # 检查前导字符防止误匹配
        if not is_space_case and leading_char_to_preserve == '.':
            idx_char_before_dot = match.start(1) - 1
            if idx_char_before_dot >= 0 and full_text[idx_char_before_dot].isdigit():
                return match.group(0) 
        
        # 检查后续字符是否为句号
        if num_end_idx_in_string < len(full_text) and full_text[num_end_idx_in_string] == '.':
            return match.group(0)
        
        try:
            number_int = int(current_number_str)
            if number_int in references_map:
                url = references_map[number_int]
                if is_space_case:
                    return f"[~{number_int}~]({url})"
                else:
                    return f"{leading_char_to_preserve}[~{number_int}~]({url})"
            else:
                return match.group(0) 
        except ValueError:
            return match.group(0)

    return citation_regex.sub(replacer, text_content)


# 处理Markdown文件的核心函数
def process_markdown_files(research_doc_path, reference_list_path, output_doc_path):
    """
    处理Markdown文件的核心流程
    
    参数:
        research_doc_path (str): 研究文档路径
        reference_list_path (str): 参考文献路径
        output_doc_path (str): 输出文件路径
    
    返回:
        tuple: (是否成功, 处理消息)
    """
    # 步骤1: 解析参考文献
    references, ref_message = parse_references(reference_list_path)
    if references is None:
        return False, ref_message

    # 步骤2: 读取研究文档
    try:
        with open(research_doc_path, 'r', encoding='utf-8') as f:
            original_content = f.read()
    except FileNotFoundError:
        return False, f"错误: 未找到研究文档 {research_doc_path}"
    except Exception as e:
        return False, f"读取研究文档时发生错误: {e}"

    # 步骤3: 替换引用
    modified_content = replace_citations_in_text(original_content, references)

    # 步骤4: 写入输出文件
    try:
        with open(output_doc_path, 'w', encoding='utf-8') as f:
            f.write(modified_content)
        return True, f"处理完成！输出文件已保存至:\n{output_doc_path}"
    except Exception as e:
        return False, f"写入输出文件时发生错误: {e}"


# GUI应用程序类
class CitationConverterApp:
    def __init__(self, master):
        self.master = master
        master.title("Markdown引用转换工具")
        master.geometry("650x450")

        # 文件路径变量
        self.research_file_path = tk.StringVar()
        self.reference_file_path = tk.StringVar()
        self.output_file_path = tk.StringVar()

        # 创建UI组件
        self.create_widgets()

    def create_widgets(self):
        """创建所有UI控件"""
        # 研究文件选择
        tk.Label(self.master, text="研究原文文件:").grid(row=0, column=0, sticky="w", padx=10, pady=5)
        self.research_entry = tk.Entry(self.master, textvariable=self.research_file_path, width=60, state='readonly')
        self.research_entry.grid(row=0, column=1, padx=5, pady=5, sticky="ew")
        tk.Button(self.master, text="选择文件", command=self.select_research_file).grid(row=0, column=2, padx=5, pady=5)

        # 参考文件选择
        tk.Label(self.master, text="参考文献文件:").grid(row=1, column=0, sticky="w", padx=10, pady=5)
        self.reference_entry = tk.Entry(self.master, textvariable=self.reference_file_path, width=60, state='readonly')
        self.reference_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        tk.Button(self.master, text="选择文件", command=self.select_reference_file).grid(row=1, column=2, padx=5, pady=5)

        # 输出文件选择
        tk.Label(self.master, text="输出文件位置:").grid(row=2, column=0, sticky="w", padx=10, pady=5)
        self.output_entry = tk.Entry(self.master, textvariable=self.output_file_path, width=60, state='readonly')
        self.output_entry.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
        tk.Button(self.master, text="保存位置", command=self.select_output_file).grid(row=2, column=2, padx=5, pady=5)

        # 转换按钮
        self.convert_button = tk.Button(self.master, text="开始转换", 
                                       command=self.run_conversion, 
                                       font=("Arial", 12, "bold"), 
                                       bg="lightblue")
        self.convert_button.grid(row=3, column=0, columnspan=3, pady=20)
        
        # 状态日志区域
        tk.Label(self.master, text="状态日志:").grid(row=4, column=0, sticky="nw", padx=10, pady=5)
        self.status_text = scrolledtext.ScrolledText(self.master, height=10, width=75, 
                                                    wrap=tk.WORD, state='disabled')
        self.status_text.grid(row=5, column=0, columnspan=3, padx=10, pady=5, sticky="ew")

        # 配置列权重
        self.master.grid_columnconfigure(1, weight=1)

    def _log_status(self, message):
        """记录状态信息到日志区域"""
        self.status_text.config(state='normal')
        self.status_text.insert(tk.END, message + "\n")
        self.status_text.see(tk.END)
        self.status_text.config(state='disabled')
        self.master.update_idletasks()

    def select_research_file(self):
        """选择研究文件对话框"""
        filetypes = (("Markdown文件", "*.md"), ("文本文件", "*.txt"), ("所有文件", "*.*"))
        filepath = filedialog.askopenfilename(title="选择研究文件", filetypes=filetypes)
        if filepath:
            self.research_file_path.set(filepath)
            self._log_status(f"已选择研究文件: {filepath}")

    def select_reference_file(self):
        """选择参考文献文件对话框"""
        filetypes = (("Markdown文件", "*.md"), ("文本文件", "*.txt"), ("所有文件", "*.*"))
        filepath = filedialog.askopenfilename(title="选择参考文献文件", filetypes=filetypes)
        if filepath:
            self.reference_file_path.set(filepath)
            self._log_status(f"已选择参考文献文件: {filepath}")

    def select_output_file(self):
        """选择输出文件保存位置"""
        original_research_filename = self.research_file_path.get()
        default_output_name = "processed_output.md"
        
        if original_research_filename:
            base, ext = os.path.splitext(os.path.basename(original_research_filename))
            default_output_name = f"{base}_带引用{ext}"

        filetypes = (("Markdown文件", "*.md"), ("所有文件", "*.*"))
        filepath = filedialog.asksaveasfilename(
            title="选择输出文件保存位置",
            initialfile=default_output_name,
            defaultextension=".md",
            filetypes=filetypes
        )
        if filepath:
            self.output_file_path.set(filepath)
            self._log_status(f"已选择输出文件路径: {filepath}")

    def run_conversion(self):
        """执行文件转换操作"""
        research_path = self.research_file_path.get()
        reference_path = self.reference_file_path.get()
        output_path = self.output_file_path.get()

        if not research_path or not reference_path or not output_path:
            messagebox.showerror("错误", "请先选择所有必要文件和输出位置")
            self._log_status("错误: 未选择完整文件路径")
            return

        self._log_status("开始处理文件...")
        self.convert_button.config(state='disabled', text="处理中...")

        # 执行文件处理
        success, message = process_markdown_files(research_path, reference_path, output_path)
        
        # 记录处理结果
        self._log_status(message)

        if success:
            messagebox.showinfo("成功", "文件转换成功！")
        else:
            messagebox.showerror("转换失败", f"处理过程中发生错误:\n\n{message.splitlines()[-1]}")

        self.convert_button.config(state='normal', text="开始转换")


if __name__ == "__main__":
    root = tk.Tk()
    app = CitationConverterApp(root)
    root.mainloop()